package com.mz.ieann.aide.widget.reward

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import com.mz.ieann.aide.R
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
import kotlin.math.abs
import kotlin.math.sqrt

/**
 * <p>------------------------------------------------------
 * <p> If there is technical discussion, you can contact zhangmz90@foxmail.com
 * <p>------------------------------------------------------
 * <p> SurfaceView的核心在于提供了两个线程：UI线程和渲染线程
 * <p> 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用，一般来说就是应用程序主线程
 * <p>
 *
 * @author Created by zhangmz
 * @date on 2023/3/8
 */
open class BaseRewardView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
): SurfaceView(context, attrs, defStyle), SurfaceHolder.Callback {

    companion object{
         const val TAG = "reward"
    }

    /**
     * 一些变量
     */
    protected val constants = RewardVar()

    /**
     * 指定的SurfaceHolder，用来获取画板
     */
    private var surfaceHolder: SurfaceHolder? = null

    /**
     * SurfaceHolder 的 canvas
     */
    private var surfaceCanvas: Canvas? = null

    /**
     * 绘制区域宽高
     */
    protected val visibleWidth by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { measuredWidth - paddingStart - paddingEnd }
    protected val visibleHeight by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { measuredHeight - paddingTop - paddingBottom }

    /**
     * 绘制区域宽高的一半
     */
    protected val w by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { visibleWidth.toFloat() / 2 }
    protected val h by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { visibleHeight.toFloat() / 2 }

    /**
     * 转盘宽的一半
     */
    protected val radius by lazy { outRectF.right - outRectF.left }

    init {
        holder.addCallback(this)
        // 设置可执行onDraw
        // setWillNotDraw(false)
        // 设置背景透明
        holder.setFormat(PixelFormat.TRANSPARENT)

        // 设置可获焦
        isClickable = true
        isFocusable = true
        isFocusableInTouchMode = true
        // 设置常亮
        keepScreenOn = true
    }

    /**
     * 扇形区域大小，值相加必须=1
     */
    protected var probability: Array<Float>? = null

    /**
     * 扇形区域文字
     */
    protected var describe: Array<String>? = null


    fun addProbability(probability: Array<Float>){
        this.probability = probability
    }

    fun addDescribe(describe: Array<String>){
        this.describe = describe
    }

    private var rewardListener: IRewardListener? = null
    fun addRewardListener(listener: IRewardListener){
        rewardListener = listener
    }

    /**
     * 单线程
     */
    private val threadPool: ThreadPoolExecutor by lazy {
        ThreadPoolExecutor(
            1,
            1,
            0L,
            TimeUnit.MILLISECONDS,
            LinkedBlockingQueue()
        )
    }

    /**
     * 用来重复绘制
     */
    private var scheduledThreadPool: ScheduledThreadPoolExecutor? = null

    override fun surfaceCreated(holder: SurfaceHolder) {
        Log.v(TAG, "surfaceCreated, holder:$holder")
        surfaceHolder = holder
        setZOrderOnTop(true)
        drawNormalcy()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        Log.v(TAG, "surfaceChanged, format:$format; width:$width; height:$height")
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        Log.v(TAG, "surfaceDestroyed, holder:$holder")
        surfaceHolder = null
        destroy()
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event?.let { e ->
            if (e.action == KeyEvent.ACTION_UP){
                return@let
            }
            val x = abs(e.x - (w + paddingStart)).toDouble()
            val y = abs(e.y - (h + paddingTop))
            val z = sqrt(x * x + y * y)
            if (z > constants.inSideRadius){
                Log.e(TAG, "没有点击到中心圆位置")
                return@let
            }
            if (scheduledThreadPool == null || scheduledThreadPool?.isShutdown == true) start() else stop()
        }?: Log.e(TAG, "touch event is null")
        return super.onTouchEvent(event)
    }

    /*********************************  以下是转盘开始和结束  ********************************/
    /*********************************  以下是转盘开始和结束  ********************************/

    /**
     * 转盘是否正在进行，true:开始转;false:停止转
     */
    private var isRunning = false

    /**
     * 开始转动的时间
     */
    private var startTime = 0L

    open fun start(){
        if (isRunning){
            Log.v(TAG, "already start, do not execute")
            return
        }
        Log.v(TAG, "---start---")
        isRunning = true
        startTime = System.currentTimeMillis()
        if (scheduledThreadPool == null){
            scheduledThreadPool = ScheduledThreadPoolExecutor(1)
        }
        val speed = (constants.drawSpeed * 10).toInt()
        scheduledThreadPool?.scheduleWithFixedDelay({
            revolveAngle = if (revolveAngle + constants.drawAngle >= 270){
                constants.initialAngle
            }else {
                revolveAngle + constants.drawAngle
            }

            drawTurntable()

            // 开始越来越快
            if (isRunning){
                if (constants.drawAngle < 100){
                    constants.drawAngle += speed
                }
                return@scheduleWithFixedDelay
            }

            // 开始越来越慢
            if (constants.drawAngle > 1){
                constants.drawAngle -= speed
            }else {
                destroy()
                calculate(revolveAngle, listener = rewardListener)
            }
        }, 0, constants.drawDInterval, TimeUnit.MILLISECONDS)
    }

    private fun stop(){
        if (!isRunning){
            Log.v(TAG, "already stop, do not execute")
            return
        }
        // 是否可以停止，防止连续点击开始按钮，卡进度
        if (System.currentTimeMillis() - startTime <= 2000){
            return
        }
        Log.v(TAG, "---stop---")
        isRunning = false
    }

    private fun destroy(){
        Log.v(TAG, "---destroy---")
        startTime = 0L
        if (scheduledThreadPool?.isShutdown == true){
            return
        }
        surfaceHolder?.unlockCanvasAndPost(surfaceCanvas)
        scheduledThreadPool?.shutdownNow()
        scheduledThreadPool = null
    }

    private fun calculate(revolveAngle: Int, listener: IRewardListener?){
        val count = probability?.size?: 0.coerceAtMost(describe?.size?: 0)
        var startAngle = revolveAngle
        for (i in 0 until count) {
            Log.v(TAG, "====>> startAngle:$startAngle; count:$count; angle:${360 * probability?.get(i)!!}")
            if (constants.initialAngle > startAngle && constants.initialAngle < (startAngle + 360 * probability?.get(i)!!)){
                Log.v(TAG, "=======================================================")
                Log.v(TAG, "============== 中奖了${describe?.get(i)} ===============")
                Log.v(TAG, "=======================================================")
            }
            startAngle += (360 * probability?.get(i)!!).toInt()
            if (startAngle > 270){ startAngle = constants.initialAngle }
        }

    }

    /*********************************  以下是绘制转盘  ********************************/
    /*********************************  以下是绘制转盘  ********************************/

    /**
     * 首次绘制
     */
    private fun drawNormalcy(){
        threadPool.execute{
            initTurntable()
        }
    }

    /**
     * 初始化转盘
     */
    private fun initTurntable(){
        surfaceCanvas = surfaceHolder?.lockCanvas()?: return
        try {
            surfaceCanvas?.let { canvas ->

                drawOutsideCircle(canvas)
                drawArc(canvas)
                drawInsidePoint(canvas)
                drawInsideCircle(canvas)

            }?: Throwable("surface canvas can not be null")
        }catch (e: Exception){
            Log.e(TAG, "drawForCreate, error:$e")
        }finally {
            surfaceHolder?.unlockCanvasAndPost(surfaceCanvas)
        }
    }

    /**
     * 绘制转盘
     */
    private fun drawTurntable(){
        surfaceCanvas = surfaceHolder?.lockCanvas()?: return
        try {
            surfaceCanvas?.let { canvas ->
                drawStart(canvas)
            }?: Throwable("surface canvas can not be null")
        }catch (e: Exception){
            Log.e(TAG, "drawForCreate, error:$e")
        }finally {
            surfaceHolder?.unlockCanvasAndPost(surfaceCanvas)
        }
    }

    /**
     * 由子类实现，可调用不同方法实现不同绘制逻辑
     */
    open fun drawStart(canvas: Canvas){

    }

    /*********************************  绘制外部环形  ********************************/

    open fun drawOutsideCircle(canvas: Canvas){
        canvas.drawArc(
            outRectF,
            0f,
            360f,
            false,
            outPaint
        )
    }

    /**
     * 外部环形区域
     */
    protected val outRectF by lazy {
        val outRingWidth = outPaint.strokeWidth
        val outSelectWidth = constants.outSideRadius.coerceAtMost(visibleHeight.coerceAtMost(visibleWidth))
        val left = (visibleWidth - outSelectWidth) / 2 + outRingWidth / 2 + paddingStart
        val top = (visibleHeight - outSelectWidth) / 2 + outRingWidth / 2 + paddingTop
        val right = left + outSelectWidth - outRingWidth
        val bottom = top + outSelectWidth - outRingWidth
        RectF(left, top, right, bottom)
    }

    /**
     * 外部画笔
     */
    private val outPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.WHITE
            strokeWidth = context.resources.getDimension(R.dimen.dp_20)
            style = Paint.Style.STROKE
        }
    }

    /*********************************  绘制扇形区  ********************************/

    /**
     * 转动角度
     */
    protected var revolveAngle = constants.initialAngle

    /**
     * 记录上一个户型的其实角度，作为下一个弧形的开始角度
     */
    protected var nextStartAngle = 0f

    open fun drawArc(canvas: Canvas){

    }

    /**
     * 绘制弧形中的文字
     */
    protected val textPaint by lazy {
        val paint = Paint()
        paint.style = Paint.Style.FILL
        paint.color = Color.WHITE
        paint.textAlign = Paint.Align.CENTER
        paint.textSize = context.resources.getDimension(R.dimen.dp_20)
        paint
    }

    /**
     * 扇形画笔
     */
    protected val lotteryPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.RED
            style = Paint.Style.FILL
        }
    }

    /*********************************  绘制箭头  ********************************/

    open fun drawInsidePoint(canvas: Canvas){
        val pointPath = Path()
        val moveX = w + paddingStart
        val moveY = h + paddingTop
        pointPath.moveTo(moveX - constants.pointSideLength, moveY)
        pointPath.lineTo(moveX + constants.pointSideLength, moveY)
        pointPath.lineTo(moveX, moveY - constants.pointSideLength * 3)
        pointPath.fillType = Path.FillType.WINDING
        canvas.drawPath(pointPath, pointPaint)
        pointPath.close()
    }

    /**
     * 指针箭头画笔
     */
    protected val pointPaint by lazy {
        // 线性渐变
        val linearGradient = LinearGradient(
            w,
            w,
            w,
            w + constants.pointSideLength * 3,
            // 颜色数组
            intArrayOf(Color.parseColor("#b2f1e8"), Color.YELLOW),
            null,
            Shader.TileMode.CLAMP
        )

        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.RED
            shader = linearGradient
            style = Paint.Style.FILL
            isFakeBoldText = true
            textSize = 30f
        }
    }

    /*********************************  绘制中心小圆  ********************************/

    /**
     * 绘制中心的可点击小圆
     */
    open fun drawInsideCircle(canvas: Canvas){
        canvas.drawCircle(w + paddingStart, h + paddingTop, constants.inSideRadius, circlePaint)
    }

    /**
     * 中心指针画笔
     */
    private val circlePaint by lazy {
        // 圆形渐变
        val radialGradient = RadialGradient(
            w + paddingStart,
            h + paddingTop,
            constants.inSideRadius,
            // 颜色数组
            intArrayOf(Color.parseColor("#113536"), Color.parseColor("#13a8a8"), Color.parseColor("#b2f1e8")),
            null,
            Shader.TileMode.CLAMP
        )
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.WHITE
            shader = radialGradient
            style = Paint.Style.FILL
        }
    }

}